﻿#pragma once

//#define _CRT_SECURE_NO_WARNINGS
//#include <stdio.h>
#include <iostream>
#include <fstream>      // for file output
#include <cmath>
#include <string>
#include <chrono>
#include <thread>
#include <future>		// 异步编程
#include <mutex>
#include <algorithm>
//#include <functional>   // for std::bind()

#define PROFING 1    // 定义一个宏，用于控制是否进行计时分析，1 为开启，0 为关闭。如果设置为开启，请务必检查代码中进行计时分析的部分之前保证调用了 Instrumented::Singleton().BeginSession(name[, filepath]); 函数和 Instrumented::Singleton().EndSession(); 函数

#if defined(PROFING) && PROFING
#define PROFILE_SCOPE(name) InstrumentationTimer timer##__LINE__(name);    // 定义一个宏，用于记录一个时间段，__LINE__ 理解为行号，作用是给不同的时间段命名
#define PROFILE_FUNCTION() PROFILE_SCOPE(__FUNCTION__)      // 定义一个宏，用于记录当前函数的运行时间，__FUNCTION__ 表示接收函数的名称（我们定义的函数的名字，不包含参数、返回类型，不是完整的函数名）
#define PROFILE_FUNCTION_FULL() PROFILE_SCOPE(__FUNCSIG__)  // 定义一个宏，用于记录当前函数的运行时间，__FUNCSIG__ 接收函数的名称（我们定义的函数的名字，含参数、返回类型、使用语法等，完整的函数名）
extern std::mutex mtx; // 定义互斥锁全局变量，用于保护共享资源
#else
    #define PROFILE_SCOPE(name)
#endif

struct ProfileResult {
    const char* Name;       // 函数名
    long long Start, End;   // 开始和结束时间
    uint32_t ThreadID;      // 线程 ID
};

struct InstrumentationSession {
    std::string Name;       // 会话名，可理解为进程名
};

class Instrumented
{
private:
    InstrumentationSession* m_CurrentSession;   // 当前会话（当前任务）
    std::ofstream m_OutputStream;               // 输出文件流
    int m_ProfileCount;                         // 计数器
public:
    Instrumented();

    void BeginSession(const std::string& sessionName, const std::string& intactFileName = "results.json");

    void EndSession();

    void SetCurrentSessionName(const std::string& name);

    void WriteProfile(const ProfileResult& result);

    void WriteHeader();

    void WriteFooter();

    static Instrumented& Singleton();
};


class InstrumentationTimer {
private:
    const char* t_name;
    std::chrono::high_resolution_clock::time_point start_time_point;
    bool t_stop;
public:
    InstrumentationTimer();
    InstrumentationTimer(const char* name);
    ~InstrumentationTimer();

    void stop();
};


extern void test_progress(void func(void), std::string name, const std::string& intactFileName = "results.json");
